#include "guiterm.hpp"
#include <dirent.h>

Session::Session(ServerConnection *host)
{
	host->attachSession(this);
	this->host = host;
	this->promptText = "$ ";
	this->currentJob = NULL;
	this->pendingInput = "";
	
	this->tab = new Tab(this);
	
	this->prompt = new CommandPrompt(this);
	
	promptVisible = false;
	
	char cwdbuf[512];
	getcwd(cwdbuf, 512);
#ifdef __MINGW32__
	// Convert backslashes to forward slashes
	for(int ii=0; cwdbuf[ii]; ii++)
		if(cwdbuf[ii]=='\\')
			cwdbuf[ii]='/';
#endif
	this->localDir = cwdbuf;
}

Session::~Session()
{
	delete prompt;
	delete tab;
	// TODO: Delete jobs
}

void Session::begin()
{
	RemoteJob *job = new RemoteJob(this);
	setCurrentJob(job);
	job->begin();
}

void Session::reportError(string message)
{
	addSegment(new MessageSegment(this, message, MessageSegment::ErrorMessage));
}

Tab *Session::getTab()
	{ return tab; }
ServerConnection *Session::getHost()
	{ return host; }
CommandPrompt *Session::getPrompt()
	{ return prompt; }
CharacterViewConfig *Session::getTerminalSettings()
	{ return &terminalSettings; }

void Session::typedCommand(string cmd)
{
	doCommand(cmd, true);
}

void Session::mousedCommand(string cmd)
{
	doCommand(cmd, true);
}

void Session::doCommand(string cmd, bool clearPrompt)
{
	hidePrompt(clearPrompt);
	
	RemoteJob *job = new RemoteJob(this, cmd);
	setCurrentJob(job);
	job->begin();
}

void Session::unconfirmedCommand(string cmd)
{
	prompt->setCommand(cmd);
	prompt->focus();
}

pair<int,int> Session::getTerminalSize(int reservedHeight)
{
	return ScrollableTermView::charsFromPixelSize(
		pair<int,int>(tab->width(), tab->height() - reservedHeight),
		&terminalSettings
	);
}

void Session::giveFocus()
{
	if(promptVisible) {
		prompt->focus();
	} else if(currentJob) {
		JobView *view = currentJob->getView();
		if(view) view->giveFocus();
	}
}

void Session::addLeftoverInput(string text)
{
	pendingInput = text;
	QTimer::singleShot(0, this, SLOT(handlePendingInput()));
}

string Session::getPromptText()
{
	return promptText;
}

RPC_HANDLER(prompt)
{
	Session *session = getSession(host, params);
	string text = params->getString("text");
	session->setPromptText(text);
}

void Session::setPromptText(string text)
{
	this->promptText = text;
	prompt->setPromptText(text);
}

RPC_HANDLER(tabcomplete)
{
	Session *session = getSession(host, params);
	string prefix = params->getString("prefix");
	string suffix = params->getString("suffix");
	session->tabCompletionReceived(prefix, suffix);
}

void Session::tabCompletionReceived(string prefix, string suffix)
{
	prompt->tabCompletionReceived(prefix, suffix);
}

bool isValidPath(string path)
{
	DIR *dir = opendir(path.c_str());
	if(dir) {
		closedir(dir);
		return true;
	} else {
		return false;
	}
}

RPC_HANDLER(lcd)
{
	Session *session = getSession(host, params);
	RemoteJob *job = getJob(host, params);
	
	string pathChange = params->getString("path");
	string oldPath = session->getLocalDir();
	
	Path newPath = Path(pathChange.c_str()).resolve(Path(oldPath.c_str()));
	
	if(isValidPath(newPath.toString())) {
		session->setLocalDir(newPath.toString());
		string message = string("Local directory is now ") + newPath.toString();
		job->reportMessage(message);
	} else {
		string message = string("Invalid path: ") + pathChange;
		job->reportError(message);
	}
}

void Session::setLocalDir(string path)
{
	this->localDir = path;
}

string Session::getLocalDir()
{
	return localDir;
}

void Session::setCurrentJob(RemoteJob *job)
{
	currentJob = job;
}

void Session::jobBackgrounded(RemoteJob *job)
{
	JobView *view = job->getView();
	showPrompt(view->isFocused());
}

void Session::jobFinished(RemoteJob *job, int result)
{
	JobView *view = job->getView();
	showPrompt(view->isFocused());
}

void Session::handlePendingInput()
{
	if(!pendingInput.length())
		return;
	
	if(currentJob && !currentJob->getIsFinished())
	{
		currentJob->sendData(pendingInput.c_str(), pendingInput.length());
		pendingInput = "";
		return;
	}
	
	for(unsigned ii=0; ii<pendingInput.length(); ii++)
	{
		if(pendingInput[ii]=='\n') {
			typedCommand(pendingInput.substr(0, ii));
			pendingInput = pendingInput.substr(ii+1, pendingInput.length()-ii-1);
			
			if(pendingInput.length())
				QTimer::singleShot(0, this, SLOT(handlePendingInput()));
			return;
		}
	}
	
	getPrompt()->setCommand(pendingInput, false);
	pendingInput = "";
}

void Session::addSegment(ViewSegment *segment)
{
	tab->appendSegment(segment);
	segment->show();
}

void Session::showPrompt(bool focus)
{
	if(!promptVisible) {
		tab->appendSegment(prompt);
		prompt->show();
		promptVisible = true;
	}
	if(focus) {
		prompt->focus();
	}
}

void Session::hidePrompt(bool reset)
{
	promptVisible = false;
	tab->removeSegment(prompt);
	prompt->hide();
	if(reset)
		prompt->reset();
}

RPC_HANDLER(exit)
{
	Session *session = getSession(host, params);
	if(session)
		session->exit();
}

void Session::exit()
{
	tab->close();
}

RPC_HANDLER(tabname)
{
	Session *session = getSession(host, params);
	string name = params->getString("name");
	
	if(session)
		session->getTab()->setName(name);
}

